home *** CD-ROM | disk | FTP | other *** search
/ Shareware Games Galore! / Shareware Games Galore!.iso / arcade / corewars / mars.c < prev    next >
Text File  |  1989-04-27  |  31KB  |  1,037 lines

  1. /*****************************************************************************
  2.  *                              MARS
  3.  *                   Memory Array Redcode Simulator
  4.  *
  5.  *    IBM PC/XT/AT Version 2.1G by Mazoft Software (DK)
  6.  *    Copyright (C) 1988, 1989 all rights reserved
  7.  *
  8.  *    Syntax: MARS <warriorA> <warriorB> (<flags> ...)
  9.  *
  10.  *    Switch    /c controls core memory size (default 4K, max 32K)
  11.  *            /s controls signature of battle (for instant replay)
  12.  *            /t controls timeout before draw (no winner)
  13.  *            /d is the debug switch (autoselects /n too)
  14.  *            /n no graphics
  15.  *            /e controls the execution speed (defaults to 0 = fastest)
  16.  *            /g override graphics board autoselect
  17.  *            /p parallel execution (defaults to OFF)
  18.  *            /8 use CoreWar 88 standard execution
  19.  *
  20.  *    MARS - Deus Ex Machina
  21.  ****************************************************************************/
  22.  
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <ctype.h>
  26. #include <fcntl.h>
  27. #include <io.h>
  28. #include <graphics.h>
  29.  
  30. #define CENTRE_TEXT CENTER_TEXT    /* Dem Yankees can't spell! */
  31. #define FSPLEN 16        /* File Specification maximum name length */
  32. #define OPCODES 11        /* Number of operation codes & pseudo instructions */
  33. #define UNKNOWN 11        /* If recognize() returns UNKNOWN, it's not listed */
  34. #define BADEXP 0x7FFF    /* bad expression */
  35. #define SYMSIZ 0x40        /* default symbol table stack space */
  36. #define MAXPRGSIZ 0x200    /* default maximum redcode program size */
  37. #define CRESIZ 0x1000    /* default core size */
  38. #define DEFTIME 5000    /* 5000 instructions * 2 before timeout */
  39. #define IMMEDIATE 0        /* addressing modes (two-bit bitfield) */
  40. #define DIRECT 1
  41. #define INDIRECT 2
  42. #define AUTODECREMENT 3
  43. #define ALL 1            /* flags for internal addressing */
  44. #define BTOB 2
  45. #define ATOB 4
  46. #define MAXSPL 64        /* max spawned tasks */
  47. #define CR putchar ('\n')
  48.  
  49. #define repeat do
  50. #define until(a) while (!(a))
  51. #define hex(i) (char)((i)+((i) > 9 ? '7' : '0'))
  52.  
  53. char *stdext = ".mrs";        /* standard MARS object code filename extension */
  54. char *copyright = "MARS System 2.0G - (C) 1988,1989 Mazoft Software (DK)\n";
  55. char *syntaxstr = "Syntax:\tMARS <warrior A> <warrior B> (<flags> ...)\nor:\tMARS -? for help";
  56. char *addrmode = "#$@<?";
  57.  
  58. enum opcodes { DAT, MOV, ADD, SUB, JMP, JMZ, JMN, DJN, CMP, SPL };
  59.  
  60. char opcode [16] [4] = {     /* List of legal REDCODE TLA-opcodes */
  61.      "DAT", "MOV", "ADD", "SUB", "JMP", "JMZ",
  62.      "JMN", "DJN", "CMP", "SPL", "???"
  63.      };
  64.  
  65. struct instructionword {
  66.     unsigned int word0;
  67.     int word1, word2;
  68.     } *core;            /* start of core */
  69.  
  70. char checkerboard [8] = {
  71.      0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55
  72.      };
  73.  
  74. int pc [2] [MAXSPL], coresize;                /* 2 * 64 pointers into the core */
  75. int task [2], tasks [2];                        /* number of active tasks */
  76. unsigned long spread [2];
  77. int lowl = 0, highl = 0;                        /* occupation range */
  78. int gmin, gmax;                            /* screen window limits */
  79. int pixelsize, xpels, ypels, maxx, maxy, xsize, ysize;
  80. int maxcolor, runflag = 0, gstat = 0;
  81. unsigned int a, mode, debug;                    /* addressing mode */
  82. char wname [2] [13], worksp [81];
  83. int dies [2];
  84. int graphmode = 0, graphdriver = DETECT;        /* the default */
  85.  
  86. main (argc, argv)
  87. int argc;
  88. char **argv;
  89. {
  90.     char c, *cp;
  91.     int i, j, k, l, m, f, qrt;
  92.     int newadr, p, winner, loser, fileindex [2], fi = 0;
  93.     int graphflag = 1, parflag = 1;
  94.     int timer = DEFTIME, delay = 0, qflag, choice;
  95.     long int signature = 0, pcycles = 0;
  96.  
  97.     time (&signature);            /* unique to every run */
  98.     lowl = highl = debug = 0;
  99.     coresize = CRESIZ;            /* default core size */
  100.     i = 2 + 1;            /* 1 command + N 2 */
  101.  
  102.     clrscr ();
  103.     centre ("-- MARS --");
  104.     centre ("Memory Array Redcode Simulator");
  105.     centre ("Version 2.1G (24-Apr-89)");
  106.     CR;
  107.     centre ("(C) Maz Spork 1988, 1989");
  108.     CR;
  109.  
  110.     for (l = 1; l < argc; l++) {
  111.  
  112.         if (argv [l] [0] == '?') {
  113.             argv [l] [0] = '-';
  114.             argv [l] [1] = '?';
  115.             }
  116.  
  117.         if (argv [l] [0] == '/' || argv [l] [0] == '-') {    /* switch identifiers */
  118.             c = tolower (argv [l] [1]);
  119.             k = argv [l] [2] ? 2 : 0;
  120.  
  121.             switch (c) {
  122.                 case 'c':
  123.                     if (!k) l++;
  124.                     coresize = atoi (&argv [l] [k]);
  125.                     break;
  126.                 case 's':
  127.                     if (!k) l++;
  128.                     signature = (long) atoi (&argv [l] [k]);
  129.                     break;
  130.                 case 't':
  131.                     if (!k) l++;
  132.                     timer = (long) atoi (&argv [l] [k]);
  133.                     break;
  134.                 case 'd':
  135.                     debug = 1;
  136.                 case 'n':
  137.                     graphflag = 0;
  138.                     break;
  139.                 case    'e':
  140.                     if (!k) l++;
  141.                     delay = atoi (&argv [l] [k]);
  142.                     break;
  143.                 case 'w':
  144.                     puts ("\nThis is a revision of the original Core Wars MARS system 1.0 by Maz Spork.");
  145.                     puts ("It is placed in the Public Domain for your benefit, and may be used or abused");
  146.                     puts ("in any way you like. If the source code is included with the assembler/simula-");
  147.                     puts ("tor, you are free to modify and enhance to your hearts content PROVIDED that");
  148.                     puts ("you NEVER charge ANY money for the software. It should NOT be sold, neither");
  149.                     puts ("in its original or in any modified form.");
  150.                     puts ("If you really like this software, and feel the urge to give some reward to the");
  151.                     puts ("brilliant programmer who wrote it, donate a generous amout of money to AIDS");
  152.                     puts ("research so we'll all survive at the end of the day.");
  153.                     puts ("If you would like information about future releases of this software, please");
  154.                     puts ("write to");
  155.                     puts ("\n\tMaz Spork, Howitzvej 21 (flat 2), DK-2000 Frederiksberg\n");
  156.                     puts ("This REDCODE/MARS sytem is compatible with what I think will be the ICWS'");
  157.                     puts ("CoreWar'88 standard - though the voting hasn't finished yet. It also employs");
  158.                     puts ("a better parallel mode, which I hope will be the standard one day. Please");
  159.                     puts ("refer to the manual for more information.");
  160.                     exit (20);
  161.                 case 'p':
  162.                     parflag = 0;
  163.                     break;
  164.                 case '8':
  165.                     puts ("Can't use CoreWar'88 standard - ICWS standards focal hasn't finished it.");
  166.                     break;
  167.                 case 'g':
  168.                     if (!k) l++;
  169.                     graphdriver = atoi (&argv [l] [k]);
  170.                     if (graphdriver == 11) graphflag = 0;
  171.                     break;
  172.                 default:
  173.                     printf ("Bad switch option %c, here's the help screen instead:\n\n", c);
  174.                 case '?':
  175.                     printf ("    Switches:\n\tC : Size of core battlefield (max 32767) (default %d)\n", CRESIZ);
  176.                     puts ("\tD : Debug mode (autoselects option N) (default off)");
  177.                     puts ("\tE : Execution speed delay roughly in 100us intervals (default 0)");
  178.                     puts ("\tN : No Graphics (default off)");
  179.                     puts ("\tP : Modified ICWS'88 mode for REAL parallel task execution");
  180.                     puts ("\tS : Signature (for identical replays) (default random)");
  181.                     printf ("\tT : Start timer (default %d)\n", DEFTIME);
  182.                     puts ("\tW : Rights and licences");
  183.                     puts ("\t8 : ICWS Standards Focal's ICWS'88 standard");
  184.                     puts ("\tG : Override auto-select on graphics board:");
  185.                     puts ("\t     0: auto-detect                  1: Color Graphics Adapter (CGA)");
  186.                     puts ("\t     2: Multi-Color Graphics (MCGA)  3: Enhanced Graphics Adapter (EGA)");
  187.                     puts ("\t     4: EGA (64 colors)              5: EGA (Monochrome)");
  188.                     puts ("\t     6: IBM 8514 graphics            7: Hercules Monochrome Graphics");
  189.                     puts ("\t     8: AT&T 400 graphics            9: Very Graphics Adapter (VGA)");
  190.                     puts ("\t    10: PC3270 graphics             11: No graphics (also option N)");
  191.                     exit (20);
  192.                     }
  193.             }
  194.         else {        /* not a switch */
  195.             fileindex [fi++] = l;
  196.             }
  197.         }
  198.  
  199.     if (fi != 2) {                /* wrong no. of parameters */
  200.         puts (syntaxstr);
  201.         exit (20);
  202.         }
  203.  
  204.     if (coresize < 0) {
  205.         printf ("Core size request too big - max 32767\n");
  206.         exit (20);
  207.         }
  208.  
  209.     CR;    /* The following 20 lines of code is awful, but it works ! */
  210.     sprintf (worksp, "     Battle Overview : %s versus %s     ", argv [*fileindex], argv [fileindex [1]]);
  211.     centre (worksp);
  212.     for (cp = worksp; *cp; *cp++) *cp = '-';
  213.     centre (worksp);
  214.     CR;
  215.     sprintf (worksp, "Coresize: %u locations", coresize);
  216.     centre (worksp);
  217.     if (timer)
  218.         sprintf (worksp, "Timeout counter starts at %u", timer);
  219.     else
  220.         sprintf (worksp, "There is no timeout");
  221.     centre (worksp);
  222.     sprintf (worksp, "Debug mode is %s", debug ? "on" : "off");
  223.     centre (worksp);
  224.     if (delay)
  225.         sprintf (worksp, "Execution delay is %u * 100us per cycle", delay);
  226.     else
  227.         sprintf (worksp, "There is no execution delay");
  228.     centre (worksp);
  229.     sprintf (worksp, "Parallelized task execution mode is %s", parflag ? "off" : "on");
  230.     centre (worksp);
  231.     sprintf (worksp, "Warrior #1 (%s) has colour ▒", argv [1]);
  232.     centre (worksp);
  233.     sprintf (worksp, "Warrior #2 (%s) has colour █", argv [2]);
  234.     centre (worksp);
  235.     sprintf (worksp, "Offcore memory has colour ░");
  236.     centre (worksp);
  237.     sprintf (worksp, "Unoccupied memory is coloured black");
  238.     centre (worksp);
  239.  
  240.     CR;
  241.     centre ("Press a key to start the battle");
  242.     while (!kbhit()); getch (); CR;
  243.  
  244.     clrscr ();
  245.     gstat = graphflag ? ginit (coresize) : 0;    /* requested no-graphics mode ? */
  246.  
  247.     if (gstat < 0) {
  248.         gclose ();
  249.         puts ("Graphic Resolution too small for requested core representation.");
  250.         gstat = 0;
  251.         }
  252.  
  253.     if (!gstat) {
  254.         wait ("Battle will commence without visual spectation (no graphics!)\n");
  255.         CR;
  256.         }
  257.  
  258.     srand ((unsigned int) signature);
  259.  
  260.     if (!(core = (struct instructionword *) malloc (sizeof (struct instructionword) * coresize))) {
  261.         gclose ();
  262.         printf ("Core memory could not be allocated (try a smaller coresize - switch c)");
  263.         exit (20);
  264.         }
  265.  
  266.     memset (core, 0, sizeof (struct instructionword) * coresize);    /* clear core */
  267.  
  268.     for (i = 0; i < 2; i++) {
  269.         pc [i] [0] = loadwarrior (argv [fileindex [i]], wname [i]);
  270.         if (gstat) {
  271.             gprintf (0, 1 + 16 * i, "%s", wname [i]);
  272.             splitbar (1, i);
  273.             }
  274.         }
  275.  
  276.     *tasks = tasks [1] = 1;    /* both start with 1 task each */
  277.     *task = task [1] = 0;        /* current tasks are both #0     */
  278.     *dies = dies [1] = *spread = spread [1] = 0;
  279.     if (!timer) timer--;
  280.  
  281. goagain:
  282.  
  283.     if (gstat)                    /* flash all program counters */
  284.         for (i = 0; i < 10; i++) {
  285.             for (k = 0; k < 2; k++)
  286.                 for (j = 0; j < tasks [k]; j++)
  287.                     gsetloc (pc [k] [j], i & 1 ? k : 3);
  288.             for (j = 0; j < 0x7FFF; j++);
  289.             }
  290.     else CR;
  291.  
  292.     runflag = 1;
  293.  
  294.     if (parflag) {                    /* for non-parallel mode */
  295.         while ((*tasks && tasks [1]) && timer && !kbhit ()) {
  296.             if (--timer < 0) timer = -1;
  297.             for (p = 0; p < 2; p++) {
  298.                 if ((newadr = execute (p, pc [p] [task [p]])) == -1) {    /* garbage collection */
  299.                     tasks [p]--;
  300.                     dies [p]++;
  301.                     for (i = task [p]; i < tasks [p] - 1; i++)
  302.                         pc [p] [i] = pc [p] [i + 1];
  303.                     splitbar (tasks [p], p);
  304.                     }
  305.                 else {
  306.                     pc [p] [task [p]] = newadr;
  307.                     task [p]++;
  308.                     }
  309.                 if (task [p] == tasks [p]) task [p] = 0;
  310.                 }
  311.             if (!gstat) printf ("%s tasks %2d, %s tasks %2d, timer = %5d%c", *wname, *tasks, wname [1], tasks [1], timer, debug ? '\n' : 13);
  312.             for (i = delay; i; i--);
  313.             pcycles++;
  314.             }
  315.         }
  316.     else {                             /* for parallel mode */
  317.         while ((*tasks && tasks [1]) && timer && !kbhit ()) {
  318.             if (--timer < 0) timer = -1;
  319.             for (p = 0; p < 2; p++) {
  320.                 for (k = tasks [p], task [p] = j = i = 0; i < k; i++) {   /* the tasks */
  321.                     if ((newadr = execute (p, pc [p] [j])) == -1) {
  322.                         tasks [p]--;
  323.                         dies [p]++;
  324.                         for (l = j; l < tasks [p]; l++)
  325.                             pc [p] [l] = pc [p] [l + 1];
  326.                         splitbar (tasks [p], p);
  327.                         }
  328.                     else pc [p] [j++] = newadr;
  329.                     task [p]++;
  330.                     }
  331.                 }
  332.             if (!gstat) printf ("%s tasks %2d, %s tasks %2d, timer = %5d%c", *wname, *tasks, wname [1], tasks [1], timer, debug ? '\n' : 13);
  333.             for (i = delay; i; i--);
  334.             pcycles++;
  335.             }
  336.         }
  337.  
  338.     choice = runflag = 0;
  339.  
  340.     if (qflag = kbhit ()) {        /* Key was pressed */
  341.         getch ();                /* Remove key */
  342.  
  343.         if (gstat) {
  344.             m = getgraphmode ();
  345.             restorecrtmode ();
  346.             }
  347.  
  348.         do {
  349.             clrscr ();
  350.             centre ("-- EXECUTION SEQUENCE HALTED --");
  351.             CR; CR;
  352.             puts ("* Battle Status:");
  353.             for (i = 0; i < 2; i++)
  354.                 printf ("   %s has %d task%s and a spread factor of %lu.\n",
  355.                         wname [i], tasks [i], tasks [i] == 1 ? "":"s", spread [i]);
  356.             if (timer != -1)
  357.                 printf ("   The timer stands at %u, interrupted after", timer);
  358.             else
  359.                 printf ("   The timer is inactive, interrupted after");
  360.             printf (" %lu cycles of execution.\n\n", pcycles);
  361.             puts ("* Choices of action:-\n");
  362.             puts ("\t0. Stop battle (no winner)");
  363.             puts ("\t1. Disassemble memory");
  364.             puts ("\t2. List warriors");
  365.             puts ("\t3. Battle analysis");
  366.             puts ("\t4. Resume battle\n");
  367.  
  368.             do {
  369.                 printf ("\015Choice: ");
  370.                 putchar (choice = getch ());
  371.                 } while (choice < '0' || choice > '4');
  372.  
  373.             choice -= '0';
  374.  
  375.             switch (choice) {
  376.                 case 1:
  377.                     disassemble_warriors (1);
  378.                     break;
  379.                 case 2:                /* Examine warriors */
  380.                     list_warriors (1);
  381.                     break;
  382.                 case 3:                /* analyze the game */
  383.                     clrscr ();
  384.                     centre ("Battle Analysis");
  385.                     CR; CR;
  386.                     for (i = 0; i < 2; i++) {
  387.                         printf ("Warrior #%d, \"%s\":\n", i, wname [i]);
  388.                         if (qrt = dies [i] + tasks [i] - 1) {
  389.                             printf ("  Regrenerates on average every %d cycles.\n", pcycles / qrt);
  390.                             printf ("  Of %d new child task%s, ", qrt, qrt==1?"":"s");
  391.                             if (dies [i]) printf ("%d ha%s not survived.\n", dies [i], dies [i] == 1 ? "s":"ve");
  392.                             else printf ("all have survived so far.\n");
  393.                             }
  394.                         else puts ("  No child tasks have been spawned");
  395.  
  396.                         for (j = 0; j < tasks [i]; j++) {
  397.                             for (f = k = 0; k < j; k++)
  398.                                 if (narrow (pc [i] [j], pc [i] [k])) f++;
  399.                             if (!f) {
  400.                                 for (k = j + 1; k < tasks [i]; k++)
  401.                                     if (narrow (pc [i] [j], pc [i] [k])) f++;
  402.                                 if (f) printf ("  There are %d warriors running suspiciously close around location %X\n", f + 1, pc [i] [j]);
  403.                                 }
  404.                             }
  405.                         CR;
  406.                         }
  407.  
  408.                     for (j = 0; j < *tasks; j++) {
  409.                         for (f = k = 0; k < tasks [1]; k++)
  410.                             if (narrow (pc [0] [j], pc [1] [k])) f++;
  411.                         if (f) printf ("%s and %s probably shares a program at location %X\n", *wname, wname [1], pc [0] [j]);
  412.                         }
  413.  
  414.                     wait (0);
  415.                     break;
  416.                 case 4:                /* resume execution */
  417.                     if (gstat) {
  418.                         setgraphmode (m);
  419.                         gdrawborder (coresize);
  420.                         for (i = 0; i < 2; i++) {
  421.                             gprintf (0, 1 + 16 * i, "%s", wname [i]);
  422.                             for (j = 0; j < tasks [i]; j++)
  423.                                 splitbar (j + 1, i);
  424.                             }
  425.                         }
  426.                     goto goagain;
  427.                 }
  428.             } while (choice);
  429.         }
  430.  
  431.     loser  = *tasks ? 1 : 0;    /* loser = !*tasks */
  432.     winner = !loser;
  433.  
  434.     if (!qflag && gstat && timer != 0) /* flash loser's last program counter */
  435.         for (i = 0; i < 10; i++)
  436.             for (k = 0; k < 2; k++) { /* 0=on, 1=off */
  437.                 gsetloc (pc [loser] [0], k ? loser : 3);
  438.                 for (j = 0; j < 0x7FFF; j++);
  439.                 }
  440.  
  441.     gclose();    /* back to normal */
  442.  
  443.     do {
  444.         clrscr ();
  445.         CR;
  446.         centre ("-- POST MORTEM --");
  447.         sprintf (worksp, "\"%s\" versus \"%s\"", *wname, wname [1]);
  448.         centre (worksp);
  449.         CR;
  450.         if (qflag) {
  451.             printf ("* The battle was interrupted externally after %lu cycles of execution.\n", pcycles);
  452.             puts ("  MARS voted the game a draw.");
  453.             }
  454.         else    if (!timer) {
  455.             puts ("* Timer exhausted. MARS interrupted the battle and voted the game a draw.");
  456.             printf ("  At this point, after %lu cycles,\n", pcycles);
  457.             printf ("   %s had %d task%s running,\n", *wname, *tasks, *tasks == 1 ? "":"s");
  458.             printf ("   %s had %d task%s running.\n", wname [1], tasks [1], tasks [1] == 1 ? "":"s");
  459.             }
  460.         else if (!*tasks && !tasks [1]) {
  461.             puts ("* Both warriors executed an undefined instruction at the same clock cycle.");
  462.             puts ("  MARS voted the game a draw.");
  463.             }
  464.         else {
  465.             puts ("* Victory!");
  466.             printf ("   %s wins the battle after %lu cycles of execution.\n", wname [winner], pcycles );
  467.             printf ("   %s executed an undefined instruction at location %X\n", wname [1 - winner], pc [1 - winner] [0]);
  468.             printf ("   %s had at that time %d active task%c\n", wname [winner], tasks [winner], tasks [winner] == 1 ? ' ' : 's');
  469.             }
  470.  
  471.         printf              ("\n\t\tSpread Factor      Reproductions      Deaths\n");
  472.         for (i = 0; i < 2; i++)
  473.             printf ("%s:      \t   %6lu             %6u         %6u\n", wname [i], spread [i], dies [i] + tasks [i] - 1, dies [i]);
  474.  
  475.         printf ("\nChoices of action:-\n\n   0. Exit MARS\n   1. Disassemble core\n   2. List surviving warriors\n\n");
  476.  
  477.         do {
  478.             putchar (13);
  479.             printf ("Select: ");
  480.             i = getch ();
  481.             } while (i < '0' || i > '2');
  482.  
  483.         putchar (i);
  484.         if (i == '1') disassemble_warriors (0);
  485.         else if (i == '2') list_warriors (0);
  486.         } while (i != '0');
  487.  
  488.     printf ("\n\nBattle signature: %d (for identical replay)\n", signature);
  489.  
  490.     free (core);    /* Get rid of this */
  491.     }
  492.  
  493.  
  494. /* list all active warrior's current execution locations (not finished)
  495.  */
  496.  
  497. list_warriors (int rm) {
  498.     int i, j, k, rmw1 = 1, rmw2 = 1;
  499.  
  500.     clrscr ();
  501.     sort (0);            /* sort the PCs */
  502.     sort (1);
  503.     centre ("Warrior Task List"); CR;
  504.     strcpy (worksp, "Task:           >               >       ");
  505.     strcpyx (&worksp [16], *wname);
  506.     strcpyx (&worksp [32], wname [1]);
  507.     puts (worksp);
  508.     puts ("---------       --------        --------");
  509.     i = *tasks, j = tasks [1], k = 0;
  510.  
  511.     if (!rm) {        /* if one is completely dead */
  512.         if (!i) { i = 1; rmw1 = 0; }
  513.         if (!j) { j = 1; rmw2 = 0; }
  514.         }
  515.  
  516.     while (i | j) {
  517.         printf ("Task #%02d :\t", k++);
  518.         if (i) printf ("@ %4X %s\t", pc [0] [--i], rmw1?"      ":"(dead)");
  519.           else printf ("\t\t");
  520.         if (j) printf ("@ %4X %s", pc [1] [--j], rmw2?"      ":"(dead)");
  521.         CR;
  522.         }
  523.     CR;
  524.     wait (0);
  525.     }
  526.  
  527. /* Generic disassembly of redcode instructions
  528.  */
  529.  
  530. disassemble_warriors (int rm) {
  531.     clrscr ();
  532.     centre ("Redcode Disassembler and core memory dump");
  533.     printf ("\nAddress (hex): ");
  534.     scanf ("%x", &a);
  535.     disassemble (a, rm);
  536.     }
  537.  
  538. sort (int player) {            /* Sort all warriors in address order */
  539.     int i, t, flag;
  540.  
  541.     if (tasks [player] < 2) return;
  542.     do {
  543.         for (flag = 0, i = 0; i < tasks [player] - 1; i++) {
  544.             if (pc [player] [i] < pc [player] [i + 1]) {
  545.                 t = pc [player] [i];
  546.                 pc [player] [i] = pc [player] [i + 1];
  547.                 pc [player] [i + 1] = t;
  548.                 flag = 1;
  549.                 }
  550.             }
  551.         } while (flag);
  552.     }
  553.  
  554. strcpyx (char *s1, char *s2) { /* like strcpy but the zero terminator is not copied */
  555.     while (*s2) *s1++ = *s2++;
  556.     }
  557.  
  558. int wait (char *s) {    /* wait ("message") or wait (NULL) */
  559.     if (s) puts (s);
  560.     printf ("Press any key to continue...");
  561.     while (!kbhit ());
  562.     getch ();
  563.     }
  564.  
  565. int execute (int player, int location) { /* returns 0 if dead, otherwise new location */
  566.     int ea1, ea2, m1, newpc = location, a;
  567.  
  568.     ea1 = effadr (location, 1, player); m1 = mode;    /* a-field effective address */
  569.     ea2 = effadr (location, 2, player);            /* b-field effective address */
  570.  
  571.     if (debug) printf ("  %s(%X) @ %X: %X %X %X : EA1 = %X (%X,%X), EA2 = %X (%X,%X)\n",
  572.                     wname [player], task [player], location, core [location].word0, core [location].word1, core [location].word2,
  573.                     ea1, core [ea1].word1, core [ea1].word2,ea2, core [ea2].word1, core [ea2].word2);
  574.  
  575.     switch (instruction (&core [location])) {
  576.         case (MOV):        /* move data from source to destination */
  577.             move (&core [ea1], &core [ea2], m1 == IMMEDIATE ? ATOB : ALL);
  578.             gsetloc (ea2, player);
  579.             newpc++;        /* go to next location */
  580.             break;
  581.         case (ADD):
  582.             add (&core [ea1], &core [ea2], m1 == IMMEDIATE ? ATOB : BTOB);
  583.             gsetloc (ea2, player);
  584.             newpc++;        /* go to next location */
  585.             break;
  586.         case (SUB):
  587.             subtract (&core [ea1], &core [ea2], m1 == IMMEDIATE ? ATOB : BTOB);
  588.             gsetloc (ea2, player);
  589.             newpc++;        /* go to next location */
  590.             break;
  591.         case (JMP):        /* use effective address */
  592.             newpc = ea1;
  593.             break;
  594.         case (JMZ):        /* only if b-field is 0 */
  595.             if (core [ea2].word2)
  596.                 newpc++;
  597.             else
  598.                 newpc = ea1;
  599.             break;
  600.         case (JMN):        /* not if b-field is 0 */
  601.             if (!core [ea2].word2)
  602.                 newpc++;
  603.             else
  604.                 newpc = ea1;
  605.             break;
  606.         case (DJN):        /* decrement b-field and use ea if not zero */
  607.             if (--core [ea2].word2)
  608.                 newpc = ea1;
  609.             else
  610.                 newpc++;
  611.             gsetloc (ea2, player);
  612.             break;
  613.         case (CMP):        /* increment pc if comparison equal */
  614.             if (compare (&core [ea1], &core [ea2], m1 == IMMEDIATE ? ATOB : ALL)) newpc++;
  615.             newpc++;
  616.             break;
  617.         case (SPL):        /* one more task */
  618.             if (tasks [player] < MAXSPL)
  619.                 pc [player] [tasks [player]++] = ea2;
  620.             else
  621.                 dies [player]++;
  622.             newpc++;
  623.             splitbar (tasks [player], player);
  624.             break;
  625.         default:            /* undefined instruction - task dies */
  626.             return (-1);
  627.         }
  628.  
  629.     return (inrange (newpc));
  630.     }
  631.  
  632. int inrange (int val) {    /* modulus supports negative numbers */
  633.     return (((val % coresize) + (val < 0 ? coresize : 0)));
  634.     }
  635.  
  636. move (source, destination, movemode)    /* move data */
  637. struct instructionword *source, *destination;
  638. int movemode;
  639. {
  640.     switch (movemode) {    /* check which move */
  641.         case (ALL):    /* whole instruction word */
  642.             destination -> word0 = source -> word0;
  643.             destination -> word1 = source -> word1;
  644.             destination -> word2 = source -> word2;
  645.             break;
  646.         case (BTOB):    /* b-field to b-field */
  647.             destination -> word0 &= 0xF0FF;
  648.             destination -> word0 |= source -> word0 & 0x0F00;
  649.             destination -> word2 = source -> word2;
  650.             break;
  651.         case (ATOB):    /* a-field to b-field */
  652.             destination -> word0 &= 0xF0FF;
  653.             destination -> word0 |= (source -> word0 & 0xF000) / 0x10;
  654.             destination -> word2 = source -> word1;
  655.         }
  656.     }
  657.  
  658. add (source, destination, addmode)    /* add data */
  659. struct instructionword *source, *destination;
  660. int addmode;
  661. {
  662.     destination -> word2 += (addmode == ATOB ? source -> word1 : source -> word2);
  663.     }
  664.  
  665. subtract (source, destination, submode)    /* subtract data */
  666. struct instructionword *source, *destination;
  667. int submode;
  668. {
  669.     destination -> word2 -= (submode == ATOB ? source -> word1 : source -> word2);
  670.     }
  671.  
  672. int compare (insa, insb, cmpmode)
  673. struct instructionword *insa, *insb;
  674. int cmpmode;
  675. {
  676.     return (cmpmode == ATOB ? (insa -> word1 == insb -> word2) : ((insa -> word0 == insb -> word0) && (insa -> word1 == insb -> word1) && (insa -> word2 == insb -> word2)));
  677.     }
  678.  
  679. int effadr (location, operand, p)    /* effective address operand 1 or 2 */
  680. int location, operand, p;
  681. {
  682.     int value, address, temp;
  683.  
  684.     if (operand == 1) {    /* extract relevant information from instruction word */
  685.         value = core [location].word1;
  686.         mode = (core [location].word0 & 0xF000) / 0x1000;
  687.         }
  688.     else {
  689.         value = core [location].word2;
  690.         mode = (core [location].word0 & 0x0F00) / 0x100;
  691.         }
  692.  
  693.     switch (mode & 3) {        /* select effective address from addressing mode and operand */
  694.         case (IMMEDIATE):
  695.             address = location;
  696.             break;
  697.         case (DIRECT):
  698.             address = location + value;
  699.             break;
  700.         case (INDIRECT):
  701.             temp = inrange (location + value);
  702.             address = core [temp].word2 + temp;
  703.             break;
  704.         case (AUTODECREMENT):
  705.             temp = inrange (location + value);
  706.             core [temp].word2--;
  707.             gsetloc (temp, p);
  708.             address = core [temp].word2 + temp;
  709.             break;
  710.         }
  711.  
  712.     return (inrange (address));
  713.     }
  714.  
  715. int instruction (inswrd)
  716. struct instructionword *inswrd;
  717. {
  718.     return ((inswrd -> word0) & 0xFF);
  719.     }
  720.  
  721. int loadwarrior (text, namedest)    /* ret's PC for this warrior */
  722. char *text, *namedest;
  723. {
  724.     int handle, i;
  725.     int prog [MAXPRGSIZ * (sizeof (struct instructionword) / sizeof (int))];
  726.     int t, loc, len, initpc, zpos, *p = prog;
  727.     char name [13];
  728.     static int hilo = 0, lastlen;
  729.  
  730.     zpos = finddot (text, name);
  731.  
  732.     if ((handle = _open (name, O_RDONLY)) == -1) {
  733.         gclose ();
  734.         printf ("\nBut \"%s\" is not present on the disk...\n", name);
  735.         exit (20);
  736.         }
  737.  
  738.     for (i = 0; i < zpos; i++) namedest [i] = toupper (name [i]);
  739.     namedest [zpos] = name [zpos] = '\0';
  740.  
  741.     if ((len = _read (handle, prog, MAXPRGSIZ * sizeof (struct instructionword))) <= 0) {
  742.         gclose ();
  743.         printf ("\n\nWould not read %s, error %d - exiting\n", name, len);
  744.         exit (20);
  745.         }
  746.  
  747.     len = (len - sizeof (int)) / sizeof (struct instructionword);    /* minus start indicator, divided by instructionword's length */
  748.     _close (handle);    /* and that's all we need */
  749.  
  750.     if (hilo) {
  751.         t = 0;
  752.         if (len + lastlen > coresize) {
  753.             gclose ();
  754.             puts ("Not enough room in core for the two warriors - exiting");
  755.             exit (20);
  756.             }
  757.         do {            /* find an unoccupied spot (tries 1024 times) */
  758.             while ((loc = rand () % coresize) <= highl && loc + len >= lowl) if (++t > 1024) {
  759.                 gclose ();
  760.                 printf ("Could not locate %s (try larger core)\n", name);
  761.                 exit (20);
  762.                 }
  763.             } while ((highl >= coresize && loc <= highl % coresize) || (loc + len - 1>= coresize && loc + len >= lowl));
  764.         }
  765.     else loc = rand () % coresize;
  766.  
  767.     initpc = ((lowl = loc) + *p++) % coresize;    /* starting location relative to physical start */
  768.     highl = lowl + len - 1;                    /* inclusive last location so minus 1 */
  769.  
  770.     for (t = len; t; t--) {
  771.         core [loc].word0 = *p++;            /* Instruction word A */
  772.         core [loc].word1 = *p++;            /* Instruction word B */
  773.         core [loc].word2 = *p++;            /* Instruction word C */
  774.         gsetloc (loc, hilo);    /* indicate occupation on memory map */
  775.         loc++; loc %= coresize;
  776.         }
  777.  
  778.     if (!gstat)
  779.         printf ("\"%s\" located from &%X to &%X (&%X bytes)\n", name, lowl, highl % coresize, len);
  780.  
  781.     hilo++;
  782.     lastlen = len;
  783.     return (initpc);
  784.     }
  785.  
  786. int finddot (name1, name2)
  787. char *name1, *name2;
  788. {
  789.     int i;
  790.     char c;
  791.  
  792.     for (i = 0; (*name2 = c = *name1++) && c != '.'; i++) name2++;
  793.     if (c)
  794.         strcpy (name2, name1 - 1);
  795.     else
  796.         strcpy (name2, stdext);    /* add extension to filename */
  797.  
  798.     return (i);
  799.     }
  800.  
  801. /* Centre string on screen */
  802.  
  803. centre (char *text) {
  804.     int i;
  805.     const screenwidth = 80;
  806.  
  807.     for (i = (screenwidth - strlen (text)) >> 1; i; i--) putchar (' ');
  808.     puts (text);
  809.     }
  810.  
  811. int sqr (int x) {
  812.     int i;
  813.     for (i = 1; i < 200; i++) if (i * i > x) break;    /* OK, it's bad */
  814.     return (i - 1);
  815.     }
  816.  
  817. int ginit (int request) {
  818.     int i;
  819.  
  820.     initgraph (&graphdriver, &graphmode, "");
  821.     if (graphresult () < 0) return (0);
  822.  
  823.     xsize = getmaxx () - 3;
  824.     ysize = getmaxy () - 32 - 3;
  825.     maxcolor = getmaxcolor ();
  826.  
  827.     pixelsize = 128;
  828.  
  829.     while (pixelsize && (xpels = xsize / pixelsize) * (ysize / pixelsize) < request)
  830.         pixelsize--;
  831.  
  832.     if (pixelsize < 3) return (-1);
  833.  
  834.     ypels = (request / xpels) + (request % xpels != 0);
  835.  
  836.     maxx = xpels * pixelsize;
  837.     maxy = ypels * pixelsize;
  838.  
  839.     gstat = 1;
  840.     gdrawborder (request);
  841.  
  842. /*    settextjustify (CENTRE_TEXT, TOP_TEXT);
  843.     settextstyle (TRIPLEX_FONT, HORIZ_DIR, 3);
  844.     outtextxy (getmaxx () / 2, 0, "Core Wars Battlefield");
  845. */
  846.     settextstyle (DEFAULT_FONT, HORIZ_DIR, 1);
  847.     settextjustify (LEFT_TEXT, TOP_TEXT);
  848.  
  849.     return (gstat);    /* success */
  850.     }
  851.  
  852. gdrawborder (int req) {
  853.     while (req % xpels) gsetloc (req++, 2);
  854.     rectangle (0, 32, maxx + 2, 32 + maxy + 2);
  855.     }
  856.  
  857. gplot (x, y, colour, p)    /* colour is 0 or 1, p is size */
  858. int x, y, colour, p;
  859. {
  860.     switch (colour) {
  861.         case 0:     setfillpattern (checkerboard, maxcolor);    /* on-off cross-hatch */
  862.                 break;
  863.         case 1:     setfillstyle (SOLID_FILL, maxcolor);
  864.                 break;
  865.         case 2:     setfillstyle (CLOSE_DOT_FILL, maxcolor);
  866.                 break;
  867.         case 3:     setfillstyle (EMPTY_FILL, BLACK);
  868.                 break;
  869.         }
  870.     bar (x, y, x + p, y + p);
  871.     }
  872.  
  873. gsetloc (loc, player)
  874. int loc, player;
  875. {
  876.     int xcoord, ycoord;
  877.  
  878.     if (runflag && player < 2) spread [player]++;
  879.     if (!gstat) return;        /* && player < 2 ??? */
  880.  
  881.     xcoord = (loc % xpels) * pixelsize + 2;
  882.     ycoord = (loc / xpels) * pixelsize + 34;
  883.     gplot (xcoord, ycoord, player, pixelsize - 2);
  884.     }
  885.  
  886. gclose () {
  887.     if (gstat) closegraph ();
  888.     }
  889.  
  890. gprintf(int x, int y, char *fmt, ...) {
  891.     va_list argptr;            /* Argument list pointer */
  892.     char str [140];            /* Buffer to build sting into */
  893.  
  894.     if (gstat) {                        /* if graphics mode */
  895.         va_start (argptr, format);        /* Initialize va_ functions */
  896.         vsprintf (str, fmt, argptr);        /* prints string to buffer */
  897.         outtextxy (x, y, str);            /* Send string in graphics mode */
  898.         va_end (argptr);                /* Close va_ functions */
  899.         }
  900.     }
  901.  
  902. splitbar (int value, int p) {
  903.     int x, y, deltax;
  904.  
  905.     if (!gstat) return;
  906.  
  907.     if (p)
  908.         setfillstyle (SOLID_FILL, maxcolor);
  909.     else
  910.         setfillpattern (checkerboard, maxcolor);
  911.  
  912.     deltax = (getmaxx() - 64) / 64;
  913.     x = 64 + deltax * value;
  914.     y = p * 16;
  915.  
  916.     if (value) bar (x, y, x + deltax - 2 , y + 8);
  917.  
  918.     setfillstyle (EMPTY_FILL, BLACK);
  919.     bar (x + deltax, y, x + 2 * deltax - 2, y + 8);
  920.     }
  921.  
  922. cleargrid () {
  923.     if (!gstat) return;
  924.     setfillstyle (EMPTY_FILL, BLACK);
  925.     bar (2, 34, maxx - 2, 32 + maxy - 2);
  926.     }
  927.  
  928. int disassemble (unsigned address, int rm) {
  929.     int i, j, f, iw, m1, m2, o1, o2, c, rm2, df;
  930.     int movin = 1;
  931.     struct instructionword *caddr;
  932.  
  933.     caddr = &core [address % coresize];
  934.  
  935.     while (movin) {
  936.         iw = caddr->word0 & 0xFF;
  937.         if (iw > 9) iw = 10;
  938.         i = caddr->word0 >> 8;
  939.         m2 = i & 0x0F;
  940.         m1 = (i >> 4) & 0x0F;
  941.         if (m1 > 3) m1 = 4;
  942.         if (m2 > 3) m2 = 4;
  943.         o1 = caddr->word1;
  944.         o2 = caddr->word2;
  945.  
  946.         itoh (address, 4, 2);
  947.         itoh (iw, 1, 1);
  948.         itoh (m1, 1, 101);
  949.         itoh (o1, 4, 1);
  950.         itoh (m2, 1, 101);
  951.         itoh (o2, 4, 3);
  952.  
  953.         for (df = f = 0, j = 0; j < 2; j++) {
  954.             rm2 = tasks [j];
  955.             if (!rm) rm2 = 1;
  956.             for (i = 0; i < rm2; i++) {
  957.                 if (pc [j] [i] == address) {
  958.                     if (f) printf ("\n\t\t\t");
  959.                     strcpy (worksp, "              ");
  960.                     if (tasks [j])
  961.                         sprintf (&worksp [24], "%s(%d):", wname [j], i);
  962.                     else {
  963.                         sprintf (&worksp [24], "%s(*):", wname [j]);
  964.                         df = 1;
  965.                         }
  966.                     strcpyx (worksp, &worksp [24]);
  967.                     printf (worksp);
  968.                     f = 1;
  969.                     }
  970.                 }
  971.             }
  972.  
  973.         if (!f) printf ("              ");
  974.         printf ("%s ", opcode [iw]);
  975.         if (iw != DAT && iw != SPL) {
  976.             diw (m1, o1, address);
  977.             if (iw != JMP) putchar (',');
  978.             }
  979.         if (iw != JMP) diw (m2, o2, address);
  980.  
  981.         if (df && (!tasks [0] || !tasks [1]))
  982.             printf ("\t<- This is where it died");
  983.  
  984.         CR;
  985.         address++;
  986.         caddr++;
  987.  
  988.         if (address == coresize) {
  989.             address = 0;
  990.             caddr = core;
  991.             }
  992.  
  993.         if (kbhit ()) {
  994.             getch ();
  995.             printf ("Stop/Continue? ");
  996.             c = getche ();
  997.             putchar (13);
  998.             if (c == 'S' || c == 's') movin = 0;
  999.             }
  1000.         }
  1001.     }
  1002.  
  1003. diw (m, v, l)
  1004. int m, v, l;
  1005. {
  1006.     if (m != 1) putchar (addrmode [m]);    /* direct addressing mode assumed */
  1007.     printf ("%d", v);
  1008.  
  1009. /*
  1010.     if (m)
  1011.         printf (" (%X)", coresize % (l + v));
  1012.     else
  1013.         printf ("       ");
  1014. */
  1015.     }
  1016.  
  1017. itoh (value, digits, spaces)      /* fast hex-print + trailing spaces*/
  1018. unsigned int value, digits, spaces;
  1019. {
  1020.     char c = ' ';
  1021.  
  1022.     while (digits--) putchar (hex (value / (1 << (digits << 2)) & 0xF));
  1023.  
  1024.      if (spaces > 100) {     /* if 10x is provided, use dashes instead */
  1025.           spaces -= 100;
  1026.           c = '-';
  1027.           }
  1028.  
  1029.     while (spaces--) putchar (c);        /* What shall we do with all the empty spaces which we used to fill ... */
  1030.      }
  1031.  
  1032. int narrow (int a, int b) {    /* boundary checking */
  1033.     const c = 4;
  1034.     return (a + c >= b && a - c <= b);
  1035.     }
  1036.  
  1037. /* End of MARS.C - see you */